import os as _os
import pathlib as _pl
from ast import literal_eval as _literal_eval

import pyg4ometry.gdml as _gd
import pyg4ometry.geant4 as _g4
import pyg4ometry.visualisation as _vi
import pyg4ometry.misc as _mi


def Test(vis=False, interactive=False, writeNISTMaterials=False, outputPath=None, refFilePath=None):
    if not outputPath:
        outputPath = _pl.Path(__file__).parent

    reg = _g4.Registry()

    # defines
    wx = _gd.Constant("wx", "100", reg, True)
    wy = _gd.Constant("wy", "100", reg, True)
    wz = _gd.Constant("wz", "100", reg, True)

    bx = _gd.Constant("bx", "10", reg, True)
    by = _gd.Constant("by", "10", reg, True)
    bz = _gd.Constant("bz", "10", reg, True)

    # materials
    if writeNISTMaterials:
        wm = _g4.nist_material_2geant4Material("G4_Galactic", reg)
        bm = _g4.nist_material_2geant4Material("G4_Au", reg)
    else:
        wm = _g4.MaterialPredefined("G4_Galactic")
        bm = _g4.MaterialPredefined("G4_Au")

    # solids
    ws = _g4.solid.Box("ws", wx, wy, wz, reg, "mm")
    bs = _g4.solid.Box("bs", bx, by, bz, reg, "mm")
    assert bs.evaluateParameterWithUnits("pX") == bx
    assert bs.evaluateParameterWithUnits("pY") == by
    assert bs.evaluateParameterWithUnits("pZ") == bz
    bs2 = _g4.solid.Box("bs2", bx, by, bz, reg, "cm")
    assert bs2.evaluateParameterWithUnits("pX") == 10 * bx
    assert bs2.evaluateParameterWithUnits("pY") == 10 * by
    assert bs2.evaluateParameterWithUnits("pZ") == 10 * bz

    # structure
    wl = _g4.LogicalVolume(ws, wm, "wl", reg)
    bl = _g4.LogicalVolume(bs, bm, "bl", reg)
    bp = _g4.PhysicalVolume([0, 0, 0], [0, 0, 0], bl, "b_pv1", wl, reg)

    # set world volume
    reg.setWorld(wl.name)

    # gdml output
    outputFile = outputPath / "T001_Box.gdml"
    w = _gd.Writer()
    w.addDetector(reg)
    w.write(outputFile)

    # check file
    _mi.compareGdmlNumericallyWithAssert(refFilePath, outputFile)

    # test __repr__
    assert str(bs) == "Box : name=bs x=10.0 y=10.0 z=10.0"

    # test
    meshInfo = bl.mesh.localmesh.info()
    # print(meshInfo)
    _mi.compareMeshInfo(
        meshInfo,
        {
            "null": False,
            "closed": True,
            "triangle": True,
            "outward": True,
            "volume": 1000.0,
            "area": 600.0,
            "numberfaces": 12,
            "numbervertices": 8,
            "minEdge": 10.0,
            "maxEdge": 14.142135623730951,
        },
    )

    # test extent of physical volume
    extentBB = wl.extent(includeBoundingSolid=True)
    extent = wl.extent(includeBoundingSolid=False)

    # visualisation
    v = None
    if vis:
        v = _vi.PubViewer()
        v.addLogicalVolume(reg.getWorldVolume())
        v.addAxes(_vi.axesFromExtents(extentBB)[0])
        v.view(interactive=interactive)

    return {"meshInfo": meshInfo, "logicalVolume": wl, "vtkViewer": v, "registry": reg}


if __name__ == "__main__":
    Test()
